/*
 * Copyright (c) 2012 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

var superlist = superlist || {};

/** Reads all options from the options cookie, if present. */
superlist.readOptions = function() {
  var optionsCookie = superlist.getCookie('options');
  if (optionsCookie) {
    superlist.readOption('options-response', optionsCookie, 1);
    superlist.readOption('options-update', optionsCookie, 3);
    superlist.readOption('options-batch', optionsCookie, 5);
  }
}

/** Reads an option into a checkbox from the cookie. */
superlist.readOption = function(checkboxId, cookie, index) {
  var checkbox = document.getElementById(checkboxId);
  checkbox.checked = (cookie.charAt(index) == '1');
}

/**
 * Reads a cookie from the cookie jar.
 */
superlist.getCookie = function(name) {
  var nameEq = name + '=';
  var cookieArray = document.cookie.split(';');
  for (var i = 0; i < cookieArray.length; i++) {
    var cookie = cookieArray[i];
    while (cookie.charAt(0) == ' ') {
      cookie = cookie.substring(1, cookie.length);
    }
    if (cookie.indexOf(nameEq) == 0) {
      return cookie.substring(nameEq.length, cookie.length);
    }
  }
  return null;
}

/**
 * Sets the options cookie based on the state of the checkboxes.
 */
superlist.setOptions = function() {
  var responseEnabled = document.getElementById('options-response').checked;
  var updateEnabled = document.getElementById('options-update').checked;
  var batchEnabled = document.getElementById('options-batch').checked;

  var optionsString = 'r' + (responseEnabled ? '1' : '0')
      + 'u' + (updateEnabled ? '1' : '0')
      + 'b' + (batchEnabled ? '1' : '0');
  document.cookie = 'options=' + optionsString;
}

/**
 * Creates a new tasklist from the current list.
 */
superlist.createTaskList = function() {
  console.log('Creating tasklist from superlist.');
  var data = {
    'id': superlist.id,
    'name': superlist.name,
    'content': {
      'items': superlist.items
    }
  }
  var createButton = document.getElementById('create-task-list');
  createButton.disabled = true;
  superlist.executeRequest('createList', data, function(status, text) {
    createButton.disabled = false;
    if (status == 200) {
      var result = JSON.parse(text);

      // Merge the tasklist and task ids into the local store.
      superlist.mergeIds(result.list.content);

      // Write the metrics from the result.
      superlist.writeMetrics(result.metrics);

      // Add tasklist to list and draw it.
      var index = superlist.tasklists.length;
      var tasklist = {'id': result.id, 'title': superlist.name};
      superlist.tasklists.push(tasklist);
      superlist.drawTaskList(index, tasklist);
    } else {
      alert("Error creating tasklist: " + text);
    }
  });
}

/**
 * Saves the current superlist to drive, as well as syncing up the tasklist and
 * calendar data.
 */
superlist.save = function() {
  console.log('Saving superlist ' + superlist.id);
  var data = {
    'id': superlist.id,
    'name': superlist.name,
    'eventIds': superlist.eventIds,
    'content': {
      'tasklistId': superlist.tasklistId,
      'eventId': superlist.eventId,
      'dueDate': superlist.dueDate,
      'items': superlist.items
    }
  };
  var saveButton = document.getElementById('save');
  saveButton.disabled = true;
  superlist.executeRequest('save', data, function(status, text) {
    saveButton.disabled = false;
    if (status == 200) {
      var result = JSON.parse(text);
      // If this was a save of a new list, redirect to the created list.
      if (superlist.id == '') {
        var id = result.id;
        var metrics = result.metrics;
        var metricsString = JSON.stringify(metrics);
        window.location = "/edit?id=" + id + "&metrics=" + metricsString;
      } else {
        superlist.mergeIds(result.list.content);
        superlist.writeMetrics(result.metrics);
      }
    } else {
      alert('Error importing tasklist: ' + text);
    }
  });
}

/**
 * Merges any ids from the content back into the local state.
 */
superlist.mergeIds = function(content) {
  console.log('Merging content...');
  if (content.tasklistId && content.tasklistId != superlist.tasklistId) {
    console.log('Setting tasklistId to ' + content.tasklistId);
    superlist.tasklistId = content.tasklistId;
  }
  if (content.eventId && content.eventId != superlist.eventId) {
    console.log('Setting list eventId to ' + content.eventId);
    superlist.eventId = content.eventId;
  }
  for (var i = 0; i < content.items.length; i++) {
    var item = content.items[i];
    var localItem = superlist.items[i];
    if (item.name == localItem.name) {
      if (item.taskId && item.taskId != localItem.taskId) {
        console.log('Setting index ' + i + ' taskId to ' + item.taskId);
        localItem.taskId = item.taskId;
      }
      if (item.eventId && item.eventId != localItem.eventId) {
        console.log('Setting index ' + i + ' eventId to ' + item.eventId);
        localItem.eventId = item.eventId;
        superlist.eventIds.push(item.eventId);
      }
    }
  }
}

/**
 * Writes a metrics object to the metrics pane.
 */
superlist.writeMetrics = function(metrics) {
  var content = '';
  for (var metric in metrics) {
    content += metric + ': ' + metrics[metric] + '<br/>';
  }
  var metricsPane = document.getElementById('metrics-pane');
  metricsPane.innerHTML = content;
}

/**
 * Executes an ajax request against the server, with the given callback.
 */
superlist.executeRequest = function(action, data, callback) {
  var request = new XMLHttpRequest();
  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      callback(request.status, request.responseText);
    }
  }
  request.open("POST", "/edit?action=" + action, true)
  request.setRequestHeader("Content-Type", "application/json");
  request.send(JSON.stringify(data));
}

/**
 * DOM save method. This saves the edited text from the input element into the
 * output element, and flips the holder and editor visibility.
 */
superlist.doSave = function(holderId, editorId, inputId, outputId) {
  var holder = document.getElementById(holderId);
  var editor = document.getElementById(editorId);
  var input = document.getElementById(inputId);
  var output = document.getElementById(outputId);

  // Update the output field.
  output.innerHTML = input.value;

  // Set the input length to the new size.
  input.setAttribute('size', input.value.length);

  // Flip the visible elements.
  holder.style.display = "block";
  editor.style.display = "none";
  return input.value;
}

/**
 * Saves the name of the list. Name must not be empty.
 */
superlist.saveName = function() {
  // Validate that name is non-empty, otherwise we don't allow this.
  var nameInput = document.getElementById('name-input');
  if (!nameInput.value) {
    alert("List Name must not be empty!");
    return;
  }
  var newName = superlist.doSave(
      'name-holder', 'name-editor', 'name-input', 'name-holder');

  // Update some other info with the new name.
  superlist.name = newName;
  document.title = newName;
}

/**
 * Saves the name of an item. If the name is empty, the item is actually
 * deleted completely.
 */
superlist.saveItemName = function(index) {
  var newName = superlist.doSave(
      'item-name-holder-' + index,
      'item-name-editor-' + index,
      'item-name-input-' + index,
      'item-name-holder-' + index);

  if (newName == '') {
    setTimeout(function() {
      superlist.deleteItem(index);
    }, 10);
  } else {
    superlist.items[index].name = newName;
  }
}

/**
 * Saves the due date of the list.
 */
superlist.saveNameDate = function() {
  var newDate = superlist.doSave('name-date-holder', 'name-date-editor',
      'name-date-input', 'name-date-holder');

  if (newDate == '') {
    // Put back in the button.
    var holder = document.getElementById('name-date-holder');
    holder.innerHTML = '<button type="submit" class="btn" id="name-date-create">Set Due Date</button>';
    var input = document.getElementById('name-date-input');
    input.setAttribute('size', '10');
    superlist.dueDate = null;
  } else {
    superlist.dueDate = newDate;
  }
}

/**
 * Saves the due date of an item in the list.
 */
superlist.saveItemDate = function(index) {
  var newDate = superlist.doSave('item-date-holder-' + index,
      'item-date-editor-' + index,
      'item-date-input-' + index,
      'item-date-holder-' + index);

  if (newDate == '') {
    var holder = document.getElementById('item-date-holder-' + index);
    holder.innerHTML = '<button type="submit" class="btn" id="item-date-create-'
      + index + '">Set Due Date</button>';
    var input = document.getElementById('item-date-input-' + index);
    input.setAttribute('size', '10');
    superlist.items[index].dueDate = null;
  } else {
    superlist.items[index].dueDate = newDate;
  }
}

/**
 * Switches to edit an item. This flips the holder and editor and sets the focus
 * and selection of the input.
 */
superlist.doEdit = function(holderId, editorId, inputId) {
  var holder = document.getElementById(holderId);
  var editor = document.getElementById(editorId);
  var input = document.getElementById(inputId);
  holder.style.display = "none";
  editor.style.display = "block";
  input.focus();
  input.select();
}

/**
 * Blurs an input element so it is no longer selected.
 */
superlist.doBlur = function(inputId) {
  var input = document.getElementById(inputId);
  input.blur();
}

/**
 * Edits the name of the list.
 */
superlist.editName = function() {
  superlist.doEdit('name-holder', 'name-editor', 'name-input');
}

/**
 * Edits the name of an item.
 */
superlist.editItemName = function(index) {
  superlist.doEdit('item-name-holder-' + index,
    'item-name-editor-' + index,
    'item-name-input-' + index);
}

/**
 * Edits the due date of the list.
 */
superlist.editNameDate = function() {
  superlist.doEdit('name-date-holder', 'name-date-editor', 'name-date-input');
}

/**
 * Edits the due date of an item in the list.
 */
superlist.editItemDate = function(index) {
  superlist.doEdit('item-date-holder-' + index,
      'item-date-editor-' + index,
      'item-date-input-' + index);
}

/**
 * Handles a key event on the name element.
 */
superlist.nameEvent = function(event) {
  if (event.keyCode == 13) {
    superlist.doBlur('name-input');
  } else if (event.keyCode == 9) {
    return superlist.selectItem(event, -1);
  } else {
    superlist.setSize('name-input');
  }
}

/**
 * Handles a key event on the main due date element.
 */
superlist.nameDateEvent = function(event) {
  if (event.keyCode == 13) {
    superlist.doBlur('name-date-input');
  }
}

/**
 * Handles a key event on an item name.
 */
superlist.itemNameEvent = function(event, index) {
  if (event.keyCode == 13) {
    superlist.doBlur("item-name-input-" + index);
  } else if (event.keyCode == 9) {
    return superlist.selectItem(event, index);
  } else {
    superlist.setSize('item-name-input-' + index);
  }
}

/**
 * Handles a key event on an item date.
 */
superlist.itemDateEvent = function(event, index) {
  if (event.keyCode == 13) {
    superlist.doBlur('item-date-input-' + index);
  }
}

/**
 * Sets the size of an input element to the number of characters it contains.
 * Not exactly accurate but close enough for a demo!
 */
superlist.setSize = function(inputId) {
  var input = document.getElementById(inputId);
  input.setAttribute('size', input.value.length);
}

/**
 * Selects an item in the list, either the name or an individual task. Handles
 * shift-tab to go backwards etc.
 */
superlist.selectItem = function(event, index) {
  if (event.shiftKey) {
    index--;
  } else {
    index++;
  }
  if (index >= superlist.items.length) {
    index = -1;
  } else if (index < -1) {
    index = superlist.items.length - 1;
  }
  if (index == -1) {
    superlist.editName();
  } else {
    superlist.editItemName(index);
  }
  if (event.preventDefault) {
    event.preventDefault();
  }
  return false;
}

/**
 * Adds a new item to the list of items and draws and selects it.
 */
superlist.addItem = function() {
  var index = superlist.items.length;
  var itemName = 'Item ' + (index + 1);
  var itemDescription = '';
  var item = {name: itemName, description: itemDescription};

  superlist.items.push(item);
  superlist.drawItem(index, item, true);
}

/**
 * Deletes an item from the list of items. Redraws the entire DOM rather than
 * attempting to handle DOM indexing correctly.
 */
superlist.deleteItem = function(index) {
  var startLength = superlist.items.length;

  // Delete item at index.
  superlist.items.splice(index, 1);

  // Clear and redraw the entire item table.
  var itemTable = document.getElementById("item-table");
  itemTable.innerHTML = '';

  superlist.drawItems();
}

/**
 * Draws an individual item into the item pane. Will always appear last.
 */
superlist.drawItem = function(index, item, edit) {
  var itemTable = document.getElementById("item-table");

  var itemRow = document.createElement('tr');
  
  // <td> for Due Date.
  var dueDateCell = document.createElement('td');
  dueDateCell.setAttribute('class', 'list-item-date');
  itemRow.appendChild(dueDateCell);

  var dueDateEditor = document.createElement('div');
  dueDateEditor.setAttribute('id', 'item-date-editor-' + index);
  dueDateEditor.setAttribute('onclick', 'superlist.editItemDate(' + index + ')');
  dueDateCell.appendChild(dueDateEditor);

  var dueDateInput = document.createElement('input');
  dueDateInput.setAttribute('type', 'date');
  dueDateInput.setAttribute('size', '10');
  dueDateInput.setAttribute('id', 'item-date-input-' + index);
  dueDateInput.setAttribute('onblur', 'superlist.saveItemDate(' + index + ')');
  dueDateInput.setAttribute('onkeydown', 'superlist.itemDateEvent(event, ' + index + ')');
  dueDateEditor.appendChild(dueDateInput);

  dueDateEditor.style.display = "none";

  var dueDateHolder = document.createElement('span');
  dueDateHolder.setAttribute('id', 'item-date-holder-' + index);
  dueDateHolder.setAttribute('onclick', 'superlist.editItemDate(' + index + ')');
  dueDateCell.appendChild(dueDateHolder);

  if (item.dueDate) {
    dueDateInput.setAttribute('value', item.dueDate);
    dueDateHolder.innerHTML = item.dueDate;
  } else {
    var dueDateCreate = document.createElement('button');
    dueDateCreate.setAttribute('type', 'submit');
    dueDateCreate.setAttribute('class', 'btn');
    dueDateCreate.setAttribute('id', 'item-date-create-' + index);
    dueDateCreate.innerHTML = "Set Due Date";
    dueDateHolder.appendChild(dueDateCreate);
  }

  // <td id="item-pane-X">...</div>
  var itemPane = document.createElement('td');
  itemPane.setAttribute('id', 'item-pane-' + index);
  itemPane.setAttribute('class', 'list-item-name');
  itemRow.appendChild(itemPane);

  // <span id="item-name-holder-X><b>X Name</b></span>
  var itemNameHolder = document.createElement('span');
  itemNameHolder.setAttribute('id', 'item-name-holder-' + index);
  itemNameHolder.setAttribute('class', 'item-name-holder');
  itemNameHolder.setAttribute('onclick', 'superlist.editItemName(' + index + ')');
  itemNameHolder.innerHTML = item.name;
  if (edit) {
    itemNameHolder.style.display = "none";
  }
  itemPane.appendChild(itemNameHolder);

  // <span id="item-name-editor-0" style="display: none">...</span>
  var itemNameEditor = document.createElement('span');
  itemNameEditor.setAttribute('id', 'item-name-editor-' + index);
  if (!edit) {
    itemNameEditor.style.display = "none";
  }
  itemPane.appendChild(itemNameEditor);

  var nameInput = document.createElement('input');
  nameInput.setAttribute('type', 'text');
  nameInput.setAttribute('id', 'item-name-input-' + index);
  nameInput.setAttribute('value', item.name);
  nameInput.setAttribute('size', item.name.length);
  nameInput.setAttribute('onblur', 'superlist.saveItemName(' + index + ')');
  nameInput.setAttribute('onkeydown', 'superlist.itemNameEvent(event, ' + index + ')');
  itemNameEditor.appendChild(nameInput);

  itemTable.appendChild(itemRow);

  if (edit) {
    nameInput.focus();
    nameInput.select();
  }
}

/**
 * Draws all items in the item pane. Does not select any of them.
 */
superlist.drawItems = function() {
  for (var i = 0; i < superlist.items.length; i++) {
    superlist.drawItem(i, superlist.items[i], false);
  }
}

/**
 * Imports a task from the task list.
 */
superlist.importTaskList = function(index) {
  var importButton = document.getElementById('import-tasklist-' + index);
  importButton.disabled = true;
  var tasklist = superlist.tasklists[index];
  console.log('Importing tasklist: ' + tasklist.title);

  var data = {
    'id': tasklist.id
  }

  superlist.executeRequest('import', data, function(status, text) {
    importButton.disabled = false;
    if (status == 200) {
      var result = JSON.parse(text);
      var id = result.id;
      var metrics = result.metrics;
      var metricsString = JSON.stringify(metrics);
      window.location = "/edit?id=" + id + "&metrics=" + metricsString;
    } else {
      alert("Error importing tasklist: " + text);
    }
  });
}

/**
 * Draws a tasklist into the tasklist table.
 */
superlist.drawTaskList = function(index, taskList) {
  var outerTable = document.getElementById('tasklist-table');

  var row = document.createElement('tr');

  var actionColumn = document.createElement('td');
  row.appendChild(actionColumn);

  var importBtn = document.createElement('button');
  importBtn.setAttribute('id', 'import-tasklist-' + index);
  importBtn.setAttribute('type', 'submit');
  importBtn.setAttribute('class', 'btn');
  importBtn.setAttribute('onclick', 'superlist.importTaskList(' + index + ')');
  importBtn.innerHTML = 'Import';
  actionColumn.appendChild(importBtn);

  // Disable the button if this list is already imported from this task list.
  // TODO(sven): Could do something nicer, like highlight?
  if (superlist.tasklistId == taskList.id) {
    importBtn.disabled = true;
  }

  var nameColumn = document.createElement('td');
  nameColumn.innerHTML = taskList.title;
  row.appendChild(nameColumn);

  outerTable.appendChild(row);
}

/**
 * Draws all tasklists in the tasklist table.
 */
superlist.drawTaskLists = function() {
  for (var i = 0; i < superlist.tasklists.length; i++) {
    superlist.drawTaskList(i, superlist.tasklists[i]);
  }
}

/**
 * Loads the items and tasklist elements.
 */
superlist.load = function() {
  superlist.readOptions();
  superlist.drawItems();
  superlist.drawTaskLists();
}
